home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / free_select.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-05-04  |  9.0 KB  |  383 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #include <glib.h>
  25.  
  26. #include "apptypes.h"
  27.  
  28. #include "appenv.h"
  29. #include "draw_core.h"
  30. #include "edit_selection.h"
  31. #include "errors.h"
  32. #include "floating_sel.h"
  33. #include "free_select.h"
  34. #include "gimage_mask.h"
  35. #include "gdisplay.h"
  36. #include "rect_select.h"
  37. #include "selection_options.h"
  38. #include "scan_convert.h"
  39.  
  40. #include "libgimp/gimpmath.h"
  41.  
  42.  
  43. #define DEFAULT_MAX_INC  1024
  44. #define SUPERSAMPLE      3
  45. #define SUPERSAMPLE2     9
  46.  
  47. /*  the free selection structures  */
  48.  
  49. typedef struct _FreeSelect FreeSelect;
  50. struct _FreeSelect
  51. {
  52.   DrawCore  *core;      /*  Core select object                      */
  53.  
  54.   SelectOps  op;        /*  selection operation (ADD, SUB, etc)     */
  55.  
  56.   gint      current_x;  /*  these values are updated on every motion event  */
  57.   gint      current_y;  /*  (enables immediate cursor updating on modifier
  58.              *   key events).  */
  59.  
  60.   gint      num_pts;    /*  Number of points in the polygon         */
  61. };
  62.  
  63.  
  64.  
  65. /*  the free selection tool options  */
  66. static SelectionOptions * free_options = NULL;
  67.  
  68. /*  The global array of XPoints for drawing the polygon...  */
  69. static GdkPoint *global_pts = NULL;
  70. static gint      max_segs = 0;
  71.  
  72.  
  73. /*  functions  */
  74.  
  75. static gint
  76. add_point (gint num_pts,
  77.        gint x,
  78.        gint y)
  79. {
  80.   if (num_pts >= max_segs)
  81.     {
  82.       max_segs += DEFAULT_MAX_INC;
  83.  
  84.       global_pts = (GdkPoint *) g_realloc ((void *) global_pts, sizeof (GdkPoint) * max_segs);
  85.  
  86.       if (!global_pts)
  87.     gimp_fatal_error ("add_point(): Unable to reallocate points array in free_select.");
  88.     }
  89.  
  90.   global_pts[num_pts].x = x;
  91.   global_pts[num_pts].y = y;
  92.  
  93.   return 1;
  94. }
  95.  
  96.  
  97. static Channel *
  98. scan_convert (GimpImage        *gimage,
  99.           gint              num_pts,
  100.           ScanConvertPoint *pts,
  101.           gint              width,
  102.           gint              height,
  103.           gboolean          antialias)
  104. {
  105.   Channel       *mask;
  106.   ScanConverter *sc;
  107.  
  108.   sc = scan_converter_new (width, height, antialias ? SUPERSAMPLE : 1);
  109.   scan_converter_add_points (sc, num_pts, pts);
  110.  
  111.   mask = scan_converter_to_channel (sc, gimage);
  112.   scan_converter_free (sc);
  113.  
  114.   return mask;
  115. }
  116.  
  117.  
  118. /*************************************/
  119. /*  Polygonal selection apparatus    */
  120.  
  121. void
  122. free_select (GImage           *gimage,
  123.          gint              num_pts,
  124.          ScanConvertPoint *pts,
  125.          SelectOps         op,
  126.          gboolean          antialias,
  127.          gboolean          feather,
  128.          gdouble           feather_radius)
  129. {
  130.   Channel *mask;
  131.  
  132.   /*  if applicable, replace the current selection  */
  133.   /*  or insure that a floating selection is anchored down...  */
  134.   if (op == SELECTION_REPLACE)
  135.     gimage_mask_clear (gimage);
  136.   else
  137.     gimage_mask_undo (gimage);
  138.  
  139.   mask = scan_convert (gimage, num_pts, pts,
  140.                gimage->width, gimage->height, antialias);
  141.  
  142.   if (mask)
  143.     {
  144.       if (feather)
  145.     channel_feather (mask, gimage_get_mask (gimage),
  146.              feather_radius,
  147.              feather_radius,
  148.              op, 0, 0);
  149.       else
  150.     channel_combine_mask (gimage_get_mask (gimage),
  151.                   mask, op, 0, 0);
  152.       channel_delete (mask);
  153.     }
  154. }
  155.  
  156. void
  157. free_select_button_press (Tool           *tool,
  158.               GdkEventButton *bevent,
  159.               gpointer        gdisp_ptr)
  160. {
  161.   GDisplay   *gdisp;
  162.   FreeSelect *free_sel;
  163.  
  164.   gdisp = (GDisplay *) gdisp_ptr;
  165.   free_sel = (FreeSelect *) tool->private;
  166.  
  167.   gdk_pointer_grab (gdisp->canvas->window, FALSE,
  168.             GDK_POINTER_MOTION_HINT_MASK |
  169.             GDK_BUTTON1_MOTION_MASK |
  170.             GDK_BUTTON_RELEASE_MASK,
  171.             NULL, NULL, bevent->time);
  172.  
  173.   tool->state = ACTIVE;
  174.   tool->gdisp_ptr = gdisp_ptr;
  175.  
  176.   switch (free_sel->op)
  177.     {
  178.     case SELECTION_MOVE_MASK:
  179.       init_edit_selection (tool, gdisp_ptr, bevent, EDIT_MASK_TRANSLATE);
  180.       return;
  181.     case SELECTION_MOVE:
  182.       init_edit_selection (tool, gdisp_ptr, bevent, EDIT_MASK_TO_LAYER_TRANSLATE);
  183.       return;
  184.     default:
  185.       break;
  186.     }
  187.  
  188.   add_point (0, bevent->x, bevent->y);
  189.   free_sel->num_pts = 1;
  190.  
  191.   draw_core_start (free_sel->core,
  192.            gdisp->canvas->window,
  193.            tool);
  194. }
  195.  
  196. void
  197. free_select_button_release (Tool           *tool,
  198.                 GdkEventButton *bevent,
  199.                 gpointer        gdisp_ptr)
  200. {
  201.   FreeSelect       *free_sel;
  202.   ScanConvertPoint *pts;
  203.   GDisplay         *gdisp;
  204.   gint              i;
  205.  
  206.   gdisp = (GDisplay *) gdisp_ptr;
  207.   free_sel = (FreeSelect *) tool->private;
  208.  
  209.   gdk_pointer_ungrab (bevent->time);
  210.   gdk_flush ();
  211.  
  212.   draw_core_stop (free_sel->core, tool);
  213.  
  214.   tool->state = INACTIVE;
  215.  
  216.   /*  First take care of the case where the user "cancels" the action  */
  217.   if (! (bevent->state & GDK_BUTTON3_MASK))
  218.     {
  219.       if (free_sel->op == SELECTION_ANCHOR)
  220.     {
  221.       /*  If there is a floating selection, anchor it  */
  222.       if (gimage_floating_sel (gdisp->gimage))
  223.         floating_sel_anchor (gimage_floating_sel (gdisp->gimage));
  224.       /*  Otherwise, clear the selection mask  */
  225.       else
  226.         gimage_mask_clear (gdisp->gimage);
  227.       
  228.       gdisplays_flush ();
  229.       return;
  230.     }
  231.  
  232.       pts = g_new (ScanConvertPoint, free_sel->num_pts);
  233.  
  234.       for (i = 0; i < free_sel->num_pts; i++)
  235.     {
  236.       gdisplay_untransform_coords_f (gdisp, 
  237.                                          global_pts[i].x, global_pts[i].y,
  238.                      &pts[i].x, &pts[i].y, FALSE);
  239.     }
  240.  
  241.       free_select (gdisp->gimage, free_sel->num_pts, pts, free_sel->op,
  242.            free_options->antialias, free_options->feather,
  243.            free_options->feather_radius);
  244.  
  245.       g_free (pts);
  246.  
  247.       gdisplays_flush ();
  248.     }
  249. }
  250.  
  251. void
  252. free_select_motion (Tool           *tool,
  253.             GdkEventMotion *mevent,
  254.             gpointer        gdisp_ptr)
  255. {
  256.   FreeSelect *free_sel;
  257.   GDisplay   *gdisp;
  258.  
  259.   gdisp = (GDisplay *) gdisp_ptr;
  260.   free_sel = (FreeSelect *) tool->private;
  261.  
  262.   /*  needed for immediate cursor update on modifier event  */
  263.   free_sel->current_x = mevent->x;
  264.   free_sel->current_y = mevent->y;
  265.  
  266.   if (tool->state != ACTIVE)
  267.     return;
  268.  
  269.   if (free_sel->op == SELECTION_ANCHOR)
  270.     {
  271.       free_sel->op = SELECTION_REPLACE;
  272.  
  273.       rect_select_cursor_update (tool, mevent, gdisp_ptr);
  274.     }
  275.  
  276.   if (add_point (free_sel->num_pts, mevent->x, mevent->y))
  277.     {
  278.       gdk_draw_line (free_sel->core->win, free_sel->core->gc,
  279.              global_pts[free_sel->num_pts - 1].x,
  280.              global_pts[free_sel->num_pts - 1].y,
  281.              global_pts[free_sel->num_pts].x,
  282.              global_pts[free_sel->num_pts].y);
  283.  
  284.       free_sel->num_pts ++;
  285.     }
  286. }
  287.  
  288. static void
  289. free_select_control (Tool       *tool,
  290.              ToolAction  action,
  291.              gpointer    gdisp_ptr)
  292. {
  293.   FreeSelect *free_sel;
  294.  
  295.   free_sel = (FreeSelect *) tool->private;
  296.  
  297.   switch (action)
  298.     {
  299.     case PAUSE:
  300.       draw_core_pause (free_sel->core, tool);
  301.       break;
  302.  
  303.     case RESUME:
  304.       draw_core_resume (free_sel->core, tool);
  305.       break;
  306.  
  307.     case HALT:
  308.       draw_core_stop (free_sel->core, tool);
  309.       break;
  310.  
  311.     default:
  312.       break;
  313.     }
  314. }
  315.  
  316. void
  317. free_select_draw (Tool *tool)
  318. {
  319.   FreeSelect *free_sel;
  320.   gint        i;
  321.  
  322.   free_sel = (FreeSelect *) tool->private;
  323.  
  324.   for (i = 1; i < free_sel->num_pts; i++)
  325.     gdk_draw_line (free_sel->core->win, free_sel->core->gc,
  326.            global_pts[i - 1].x, global_pts[i - 1].y,
  327.            global_pts[i].x, global_pts[i].y);
  328. }
  329.  
  330. static void
  331. free_select_options_reset (void)
  332. {
  333.   selection_options_reset (free_options);
  334. }
  335.  
  336. Tool *
  337. tools_new_free_select (void)
  338. {
  339.   Tool       *tool;
  340.   FreeSelect *private;
  341.  
  342.   /*  The tool options  */
  343.   if (!free_options)
  344.     {
  345.       free_options =
  346.     selection_options_new (FREE_SELECT, free_select_options_reset);
  347.       tools_register (FREE_SELECT, (ToolOptions *) free_options);
  348.     }
  349.  
  350.   tool = tools_new_tool (FREE_SELECT);
  351.   private = g_new0 (FreeSelect, 1);
  352.  
  353.   private->core    = draw_core_new (free_select_draw);
  354.   private->num_pts = 0;
  355.   private->op      = SELECTION_REPLACE;
  356.  
  357.   tool->scroll_lock = TRUE;   /*  Do not allow scrolling  */
  358.  
  359.   tool->private = (void *) private;
  360.  
  361.   tool->button_press_func   = free_select_button_press;
  362.   tool->button_release_func = free_select_button_release;
  363.   tool->motion_func         = free_select_motion;
  364.   tool->arrow_keys_func     = rect_select_arrow_keys;
  365.   tool->modifier_key_func   = rect_select_modifier_update;
  366.   tool->cursor_update_func  = rect_select_cursor_update;
  367.   tool->oper_update_func    = rect_select_oper_update;
  368.   tool->control_func        = free_select_control;
  369.  
  370.   return tool;
  371. }
  372.  
  373. void
  374. tools_free_free_select (Tool *tool)
  375. {
  376.   FreeSelect *free_sel;
  377.  
  378.   free_sel = (FreeSelect *) tool->private;
  379.  
  380.   draw_core_free (free_sel->core);
  381.   g_free (free_sel);
  382. }
  383.